package com.lmk.mkcc.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.lmk.mkcc.domain.Course;
import com.lmk.mkcc.domain.CourseMarket;
import com.lmk.mkcc.domain.CourseOrder;
import com.lmk.mkcc.domain.CourseOrderItem;
import com.lmk.mkcc.dto.CourseOrderDto;
import com.lmk.mkcc.dto.PayDto;
import com.lmk.mkcc.dto.PayextparamsDto;
import com.lmk.mkcc.enums.GlobalErrorCode;
import com.lmk.mkcc.feign.CourseService;
import com.lmk.mkcc.mapper.CourseOrderMapper;
import com.lmk.mkcc.result.JSONResult;
import com.lmk.mkcc.service.ICourseOrderItemService;
import com.lmk.mkcc.service.ICourseOrderService;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.lmk.mkcc.util.AssertUtil;
import com.lmk.mkcc.util.CodeGenerateUtils;
import com.lmk.mkcc.vo.CourseInfoVo;
import com.lmk.mkcc.vo.CourseOrderVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.client.producer.SendStatus;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author kun
 * @since 2022-10-16
 */
@Service
@Slf4j
public class CourseOrderServiceImpl extends ServiceImpl<CourseOrderMapper, CourseOrder> implements ICourseOrderService {
    @Autowired
    private RocketMQTemplate rocketMQTemplate;
    @Autowired
    private ICourseOrderItemService courseOrderItemService;
    @Autowired
    private CourseService courseService;
    @Autowired
    private RedisTemplate<Object,Object> redisTemplate;
    private String redisOrderToken = "orderToken:%s:%s";
    @Override
    public String placeOrder(CourseOrderDto courseOrderDto) {
        // 获取dto中所有对象
        List<Long> courseIds = courseOrderDto.getCourseIds();
        Integer payType = courseOrderDto.getPayType();
        String token = courseOrderDto.getToken();
        Integer type = courseOrderDto.getType();
        // 用流的方式将list转化为string
        /*String idsStr = courseIds.stream().map(id -> String.valueOf(id)).collect(Collectors.joining(","));*/
        // 比较瓦的办法，用stringutils
        String str = StringUtils.join(courseIds, ",");
        // 定义一个loinId
        Long loginId = 3L;
        // 获取key
        String key = String.format(redisOrderToken, loginId, str);
        // 获取redis中保存的token
        Object o = redisTemplate.opsForValue().get(key);
        AssertUtil.isNotNull(o, GlobalErrorCode.NO_REDISTOKEN_ERROR);
        String redistoken = o.toString();
        boolean equals = token.equals(redistoken);
        AssertUtil.isTrue(equals,GlobalErrorCode.TOKEN_DIFFERENT_ERROR);

        // 获取课程信息
        JSONResult getinfo = courseService.getinfo(str);
        AssertUtil.isTrue(getinfo.isSuccess(),GlobalErrorCode.NO_INFO_ERROR);
        // 获取data信息，并判断是否为空
        Object data = getinfo.getData();
        AssertUtil.isNotNull(data,GlobalErrorCode.NO_INFODATA_ERROR);
        // 将data转化为courseinfovo对象
        CourseInfoVo courseInfoVo = JSON.parseObject(JSON.toJSONString(data), CourseInfoVo.class);
        // 分别保存到t_course_order和t_course_order_item两张表
        List<CourseOrderVo> courseInfos = courseInfoVo.getCourseInfos();
        BigDecimal totalAmount = courseInfoVo.getTotalAmount();

        // 先保存到t_course_order中
        CourseOrder courseOrder = new CourseOrder();
        // 创建时间
        courseOrder.setCreateTime(new Date());
        // 支付方式
        courseOrder.setPayType(payType);
        // 订单编号
        courseOrder.setOrderNo(CodeGenerateUtils.generateOrderSn(loginId));
        // 订单状态
        courseOrder.setStatusOrder(CourseOrder.WAIT_PAY);
        // 订单金额
        courseOrder.setTotalAmount(totalAmount);
        // userid
        courseOrder.setUserId(loginId);
        // 购买数量
        courseOrder.setTotalCount(courseInfos.size());
        // 是秒杀还是普通订单
        courseOrder.setVersion(0);

        /*// 保存到courseorder
        insert(courseOrder);*/

        // 保存到t_course_order_item表
        String title = "购买课程 [%s;] , 支付[%s] 元";
        List<String> coursename = new ArrayList<>();
        for (CourseOrderVo courseInfo : courseInfos) {

            /*购买课程 [java大神班;] , 支付[100.00] 元*/
            Course course = courseInfo.getCourse();
            CourseMarket courseMarket = courseInfo.getCourseMarket();
            CourseOrderItem courseOrderItem = new CourseOrderItem();
            courseOrderItem.setAmount(courseMarket.getPrice());
            courseOrderItem.setCount(1);
            courseOrderItem.setCourseId(course.getId());
            // 课程名字
            courseOrderItem.setCourseName(course.getName());
            // 课程价格
            courseOrderItem.setCoursePic(course.getPic());
            courseOrderItem.setCreateTime(new Date());
            courseOrderItem.setOrderId(courseOrder.getId());
            courseOrderItem.setOrderNo(courseOrder.getOrderNo());
            courseOrderItem.setVersion(0);

            /*courseOrderItemService.insert(courseOrderItem);*/
            courseOrder.getCourseOrderItems().add(courseOrderItem);
            coursename.add(course.getName());
        }

        String coursenames = StringUtils.join(coursename, ",");
        String format = String.format(title, coursenames, totalAmount);
        courseOrder.setTitle(format);


        /*updateById(courseOrder);*/

        PayDto payDto = new PayDto();
        payDto.setUserId(loginId);
        payDto.setExtParams(null);
        payDto.setOrderNo(courseOrder.getOrderNo());
        payDto.setPayType(payType);
        payDto.setTitle(format);
        payDto.setTotalAmount(totalAmount);

/*-----------------------------------------异步回调板块-----------------------------------------------------*/

        // 使用ext_params额外参数字，所以要在这里使用一个PayextparamsDto来接收参数
        PayextparamsDto payextparamsDto = new PayextparamsDto();
        // 将参数放入dto中
        payextparamsDto.setCourseIds(str);
        payextparamsDto.setUserId(loginId);
        payextparamsDto.setOrderNo(courseOrder.getOrderNo());
        // 将payextparamsDto转化为一个字符串
        payDto.setExtParams(JSON.toJSONString(payextparamsDto));
/*--------------------------------------------------------------------------------------------------*/

        // 创建一个消息对象
        Message<String> message = MessageBuilder.withPayload(JSON.toJSONString(payDto)).build();
        // 发送事务消息
        rocketMQTemplate.sendMessageInTransaction(
          "corse-order-sw-producer-group",
                "corse-order-sw-topic:corse-order-sw-tag",
                message,
                JSON.toJSONString(courseOrder)
        );

        // 删除redis中key
        redisTemplate.delete(key);
/*----------------------------------------发送超时，延时消息-----------------------------------------------*/
        try {
            // 创建消息对象
            Message<String> message2 = MessageBuilder.withPayload(courseOrder.getOrderNo()).build();
            // 发送延时消息
            SendResult sendResult = rocketMQTemplate.syncSend(
                    "overtime-delayed-topic:overtime-delayed-tag",
                    message2,
                    3000,
                    3
            );

            if (!sendResult.getSendStatus().equals(SendStatus.SEND_OK)){
                log.error("延迟消息发送失败，订单号为：{}",courseOrder.getOrderNo());
            }

        } catch (Exception e) {
            log.error("延迟消息发送失败，订单号为：{}",courseOrder.getOrderNo());
            e.printStackTrace();
        }



        /*--------------------------------------------------------------------------------------------------*/

        return courseOrder.getOrderNo();
    }

    @Override
    public CourseOrder getByorderNo(String orderNo) {
        EntityWrapper<CourseOrder> wrapper = new EntityWrapper<>();
        wrapper.eq("order_no",orderNo);
        return selectOne(wrapper);
    }

    @Override
    public void addCourseOrderAndCourseOrderItem(CourseOrder courseOrder) {
        if (getByorderNo(courseOrder.getOrderNo()) == null){
            insert(courseOrder);
            List<CourseOrderItem> courseOrderItems = courseOrder.getCourseOrderItems();
            for (CourseOrderItem courseOrderItem : courseOrderItems) {
                courseOrderItem.setOrderId(courseOrder.getId());
                courseOrderItemService.insert(courseOrderItem);
            }
        }
    }


}
